import { childEnglishApi } from '@/api/childEnglishApi';
import CryptoJS from 'crypto-js';

/**
 * 分片管理器 - 管理大文件的分片上传和下载
 */
class ChunkManager {
  constructor() {
    this.uploads = new Map();
    this.downloads = new Map();
    this.defaultChunkSize = 5 * 1024 * 1024; // 5MB
    this.maxConcurrentChunks = 3;
    this.maxRetries = 3;
  }

  /**
   * 上传文件（分片方式）
   */
  async uploadFile(file, fileMd5, chunkSize = null, options = {}) {
    const {
      onProgress = null,
      onChunkProgress = null,
      onChunkComplete = null,
      onError = null,
      fileType = null
    } = options;

    const uploadId = this.generateUploadId(file, fileMd5);
    const actualChunkSize = chunkSize || this.defaultChunkSize;
    const totalChunks = Math.ceil(file.size / actualChunkSize);

    // 创建上传任务
    const uploadTask = {
      id: uploadId,
      file,
      fileMd5,
      chunkSize: actualChunkSize,
      totalChunks,
      uploadedChunks: 0,
      progress: 0,
      status: 'uploading',
      chunks: {},
      startTime: Date.now()
    };

    this.uploads.set(uploadId, uploadTask);

    try {
      // 检查分片状态
      const chunkStatus = await this.checkChunkStatus(uploadTask);

      // 如果文件已存在，直接完成
      if (chunkStatus.status === 'completed') {
        this.completeUpload(uploadTask, chunkStatus);
        return chunkStatus;
      }

      // 上传分片
      await this.uploadChunks(uploadTask, {
        onChunkProgress,
        onChunkComplete
      });

      // 合并分片
      const result = await this.mergeChunks(uploadTask, { fileType });

      this.completeUpload(uploadTask, result);
      return result;

    } catch (error) {
      this.handleUploadError(uploadTask, error, onError);
      throw error;
    }
  }

  /**
   * 检查分片状态
   */
  async checkChunkStatus(uploadTask) {
    try {
      const response = await childEnglishApi.checkChunkStatus({
        fileMd5: uploadTask.fileMd5,
        fileName: uploadTask.file.name,
        fileSize: uploadTask.file.size,
        chunkSize: uploadTask.chunkSize,
        totalChunks: uploadTask.totalChunks
      });

      // 更新已上传的分片
      if (response.data && response.data.uploadedChunks) {
        uploadTask.uploadedChunks = response.data.uploadedChunks.length;
        uploadTask.progress = (uploadTask.uploadedChunks / uploadTask.totalChunks) * 100;

        response.data.uploadedChunks.forEach(chunkNumber => {
          uploadTask.chunks[chunkNumber] = 'completed';
        });
      }

      return response.data;

    } catch (error) {
      console.error('检查分片状态失败:', error);
      throw error;
    }
  }

  /**
   * 上传所有分片
   */
  async uploadChunks(uploadTask, options) {
    const { onChunkProgress, onChunkComplete } = options;
    const promises = [];

    for (let chunkNumber = 1; chunkNumber <= uploadTask.totalChunks; chunkNumber++) {
      // 跳过已上传的分片
      if (uploadTask.chunks[chunkNumber] === 'completed') {
        continue;
      }

      // 控制并发数量
      if (promises.length >= this.maxConcurrentChunks) {
        await Promise.race(promises);
      }

      const promise = this.uploadChunkWithRetry(uploadTask, chunkNumber, {
        onChunkProgress,
        onChunkComplete
      });

      promises.push(promise);
    }

    // 等待所有分片完成
    await Promise.all(promises);
  }

  /**
   * 上传单个分片（带重试）
   */
  async uploadChunkWithRetry(uploadTask, chunkNumber, options) {
    const { onChunkProgress, onChunkComplete } = options;

    let retryCount = 0;

    while (retryCount <= this.maxRetries) {
      try {
        await this.uploadSingleChunk(uploadTask, chunkNumber, onChunkProgress);

        // 分片上传成功
        uploadTask.chunks[chunkNumber] = 'completed';
        uploadTask.uploadedChunks++;
        uploadTask.progress = (uploadTask.uploadedChunks / uploadTask.totalChunks) * 100;

        if (onChunkComplete) {
          onChunkComplete(chunkNumber);
        }

        return;

      } catch (error) {
        retryCount++;

        if (retryCount > this.maxRetries) {
          throw new Error(`分片 ${chunkNumber} 上传失败: ${error.message}`);
        }

        console.warn(`分片 ${chunkNumber} 上传失败，第 ${retryCount} 次重试`);
        await this.delay(1000 * retryCount);
      }
    }
  }

  /**
   * 上传单个分片
   */
  async uploadSingleChunk(uploadTask, chunkNumber, onChunkProgress) {
    const start = (chunkNumber - 1) * uploadTask.chunkSize;
    const end = Math.min(start + uploadTask.chunkSize, uploadTask.file.size);
    const chunkBlob = uploadTask.file.slice(start, end);

    const chunkData = {
      fileMd5: uploadTask.fileMd5,
      fileName: uploadTask.file.name,
      chunkNumber: chunkNumber,
      totalChunks: uploadTask.totalChunks,
      chunkSize: uploadTask.chunkSize,
      fileSize: uploadTask.file.size
    };

    return await childEnglishApi.uploadChunk(
      chunkData,
      chunkBlob,
      onChunkProgress
    );
  }

  /**
   * 合并分片
   */
  async mergeChunks(uploadTask, options = {}) {
    try {
      // 获取当前用户信息（只从sessionStorage读取）
      const userData = sessionStorage.getItem('user');
      const user = userData ? JSON.parse(userData) : null;
      const uploadUser = user ? user.username : null;

      // 根据文件扩展名判断文件类型
      const fileName = uploadTask.file.name;
      const extension = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase();
      let fileType = options.fileType || null;
      if (!fileType) {
        if (['pdf', 'ppt', 'pptx', 'doc', 'docx', 'txt'].includes(extension)) {
          fileType = 'courseware';
        } else if (['jpg', 'jpeg', 'png', 'gif', 'pdf'].includes(extension)) {
          fileType = 'picturebook';
        } else if (['mp3', 'wav', 'ogg', 'flac', 'aac', 'm4a', 'wma', 'mp4'].includes(extension)) {
          fileType = 'audio';
        }
      }

      const response = await childEnglishApi.mergeChunks({
        fileMd5: uploadTask.fileMd5,
        fileName: uploadTask.file.name,
        totalChunks: uploadTask.totalChunks,
        uploadUser: uploadUser,
        fileType: fileType
      });

      return response.data;

    } catch (error) {
      console.error('合并分片失败:', error);
      throw error;
    }
  }

  /**
   * 完成上传
   */
  completeUpload(uploadTask, result) {
    uploadTask.status = 'completed';
    uploadTask.progress = 100;
    uploadTask.endTime = Date.now();
    uploadTask.result = result;

    // 清理上传记录（保留一段时间供查询）
    setTimeout(() => {
      this.uploads.delete(uploadTask.id);
    }, 30000);
  }

  /**
   * 处理上传错误
   */
  handleUploadError(uploadTask, error, onError) {
    uploadTask.status = 'error';
    uploadTask.error = error;

    if (onError) {
      onError(error);
    }

    console.error('文件上传失败:', error);
  }

  /**
   * 下载文件（分片方式，支持断点续传）
   */
  async downloadFile(fileName, url, options = {}) {
    const {
      onProgress = null,
      onChunkProgress = null,
      onComplete = null,
      onError = null,
      chunkSize = null
    } = options;

    const downloadId = this.generateDownloadId(fileName);
    const actualChunkSize = chunkSize || this.defaultChunkSize;

    // 创建下载任务
    const downloadTask = {
      id: downloadId,
      fileName,
      url,
      chunkSize: actualChunkSize,
      status: 'downloading',
      progress: 0,
      downloadedSize: 0,
      startTime: Date.now(),
      chunks: {}
    };

    this.downloads.set(downloadId, downloadTask);

    try {
      // 获取文件信息
      const fileInfo = await this.getFileInfo(fileName);
      downloadTask.totalSize = fileInfo.fileSize;
      downloadTask.totalChunks = Math.ceil(fileInfo.fileSize / actualChunkSize);

      // 下载分片
      const blob = await this.downloadChunks(downloadTask, {
        onChunkProgress,
        onProgress
      });

      // 完成下载
      this.completeDownload(downloadTask, blob);

      if (onComplete) {
        onComplete(blob);
      }

      return blob;

    } catch (error) {
      this.handleDownloadError(downloadTask, error, onError);
      throw error;
    }
  }

  /**
   * 获取文件信息
   */
  async getFileInfo(fileName) {
    try {
      const response = await childEnglishApi.getDownloadInfo(fileName);
      return response.data;
    } catch (error) {
      console.error('获取文件信息失败:', error);
      throw error;
    }
  }

  /**
   * 下载所有分片
   */
  async downloadChunks(downloadTask, options) {
    const { onChunkProgress, onProgress } = options;
    const chunks = [];
    const promises = [];

    for (let chunkNumber = 1; chunkNumber <= downloadTask.totalChunks; chunkNumber++) {
      // 控制并发数量
      if (promises.length >= this.maxConcurrentChunks) {
        await Promise.race(promises);
      }

      const promise = this.downloadChunkWithRetry(downloadTask, chunkNumber, {
        onChunkProgress,
        onProgress
      }).then(chunkData => {
        chunks[chunkNumber - 1] = chunkData;
        downloadTask.downloadedSize += chunkData.size;
      });

      promises.push(promise);
    }

    await Promise.all(promises);

    // 合并分片
    return this.mergeDownloadChunks(chunks);
  }

  /**
   * 下载单个分片（带重试）
   */
  async downloadChunkWithRetry(downloadTask, chunkNumber, options) {
    const { onChunkProgress, onProgress } = options;

    let retryCount = 0;

    while (retryCount <= this.maxRetries) {
      try {
        const chunkData = await this.downloadSingleChunk(
          downloadTask,
          chunkNumber,
          onChunkProgress
        );

        // 更新进度
        if (onProgress) {
          const progress = (downloadTask.downloadedSize + chunkData.size) / downloadTask.totalSize * 100;
          onProgress(progress);
        }

        return chunkData;

      } catch (error) {
        retryCount++;

        if (retryCount > this.maxRetries) {
          throw new Error(`分片 ${chunkNumber} 下载失败: ${error.message}`);
        }

        await this.delay(1000 * retryCount);
      }
    }
  }

  /**
   * 下载单个分片
   */
  async downloadSingleChunk(downloadTask, chunkNumber, onChunkProgress) {
    const start = (chunkNumber - 1) * downloadTask.chunkSize;
    const end = Math.min(start + downloadTask.chunkSize, downloadTask.totalSize) - 1;
    const range = `bytes=${start}-${end}`;

    const response = await childEnglishApi.downloadFile(
      downloadTask.fileName,
      range,
      onChunkProgress
    );

    return {
      data: response.data,
      size: parseInt(response.headers['content-length'] || '0'),
      chunkNumber: chunkNumber
    };
  }

  /**
   * 合并下载的分片
   */
  mergeDownloadChunks(chunks) {
    // 按分片顺序排序
    const sortedChunks = chunks.filter(chunk => chunk).sort((a, b) => a.chunkNumber - b.chunkNumber);

    // 创建Blob数组
    const blobArrays = sortedChunks.map(chunk => chunk.data);

    // 合并Blob
    return new Blob(blobArrays);
  }

  /**
   * 完成下载
   */
  completeDownload(downloadTask, blob) {
    downloadTask.status = 'completed';
    downloadTask.progress = 100;
    downloadTask.endTime = Date.now();
    downloadTask.blob = blob;

    // 清理下载记录
    setTimeout(() => {
      this.downloads.delete(downloadTask.id);
    }, 30000);
  }

  /**
   * 处理下载错误
   */
  handleDownloadError(downloadTask, error, onError) {
    downloadTask.status = 'error';
    downloadTask.error = error;

    if (onError) {
      onError(error);
    }

    console.error('文件下载失败:', error);
  }

  /**
   * 暂停上传
   */
  pauseUpload(uploadId) {
    const uploadTask = this.uploads.get(uploadId);
    if (uploadTask) {
      uploadTask.status = 'paused';
    }
  }

  /**
   * 恢复上传
   */
  resumeUpload(uploadId) {
    const uploadTask = this.uploads.get(uploadId);
    if (uploadTask) {
      uploadTask.status = 'uploading';
    }
  }

  /**
   * 取消上传
   */
  cancelUpload(uploadId) {
    const uploadTask = this.uploads.get(uploadId);
    if (uploadTask) {
      uploadTask.status = 'cancelled';

      // 清理服务器上的临时分片
      if (uploadTask.fileMd5) {
        childEnglishApi.cleanupChunks(uploadTask.fileMd5).catch(console.error);
      }

      this.uploads.delete(uploadId);
    }
  }

  /**
   * 暂停下载
   */
  pauseDownload(downloadId) {
    const downloadTask = this.downloads.get(downloadId);
    if (downloadTask) {
      downloadTask.status = 'paused';
    }
  }

  /**
   * 恢复下载
   */
  resumeDownload(downloadId) {
    const downloadTask = this.downloads.get(downloadId);
    if (downloadTask) {
      downloadTask.status = 'downloading';
    }
  }

  /**
   * 取消下载
   */
  cancelDownload(downloadId) {
    const downloadTask = this.downloads.get(downloadId);
    if (downloadTask) {
      downloadTask.status = 'cancelled';
      this.downloads.delete(downloadId);
    }
  }

  /**
   * 计算文件MD5（使用CryptoJS）
   */
  async calculateFileMD5(file) {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();

      reader.onload = (e) => {
        try {
          const buffer = e.target.result;
          const wordArray = this.arrayBufferToWordArray(buffer);
          const md5 = CryptoJS.MD5(wordArray).toString();
          resolve(md5);
        } catch (error) {
          reject(error);
        }
      };

      reader.onerror = reject;
      reader.readAsArrayBuffer(file);
    });
  }

  /**
   * ArrayBuffer转WordArray（CryptoJS格式）
   */
  arrayBufferToWordArray(arrayBuffer) {
    const u8 = new Uint8Array(arrayBuffer);
    const len = u8.length;
    const words = [];

    for (let i = 0; i < len; i++) {
      words[i >>> 2] |= (u8[i] & 0xff) << (24 - (i % 4) * 8);
    }

    return CryptoJS.lib.WordArray.create(words, len);
  }

  /**
   * 生成上传ID
   */
  generateUploadId(file, fileMd5) {
    return `upload_${fileMd5}_${file.name}_${file.size}`;
  }

  /**
   * 生成下载ID
   */
  generateDownloadId(fileName) {
    return `download_${fileName}_${Date.now()}`;
  }

  /**
   * 获取上传任务
   */
  getUploadTask(uploadId) {
    return this.uploads.get(uploadId);
  }

  /**
   * 获取下载任务
   */
  getDownloadTask(downloadId) {
    return this.downloads.get(downloadId);
  }

  /**
   * 获取所有上传任务
   */
  getAllUploads() {
    return Array.from(this.uploads.values());
  }

  /**
   * 获取所有下载任务
   */
  getAllDownloads() {
    return Array.from(this.downloads.values());
  }

  /**
   * 设置分片大小
   */
  setChunkSize(chunkSize) {
    this.defaultChunkSize = chunkSize;
  }

  /**
   * 设置最大并发数
   */
  setMaxConcurrentChunks(max) {
    this.maxConcurrentChunks = Math.max(1, max);
  }

  /**
   * 设置最大重试次数
   */
  setMaxRetries(max) {
    this.maxRetries = Math.max(0, max);
  }

  /**
   * 延迟函数
   */
  delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  /**
   * 清理过期的任务
   */
  cleanupExpiredTasks(expireTime = 3600000) { // 默认1小时
    const now = Date.now();

    // 清理上传任务
    this.uploads.forEach((task, id) => {
      if (task.endTime && (now - task.endTime > expireTime)) {
        this.uploads.delete(id);
      }
    });

    // 清理下载任务
    this.downloads.forEach((task, id) => {
      if (task.endTime && (now - task.endTime > expireTime)) {
        this.downloads.delete(id);
      }
    });
  }
}

// 创建单例实例
export const chunkManager = new ChunkManager();
export default chunkManager;
